--[[
     Created by IntelliJ IDEA.
     User: 毛凯
     Date: 2018/7/30
     Time: 9:38
     计算随机红包额度
     参数： act 活动id
     参数： remaining 当前余额
     参数： min 随机数目的最小值，单位分
     参数： max 随机数目的最大值，单位分
     参数：center 发放的中心点，单位分
     返回：额度（单位 分）
     注意：函数内部会自动创建以下变量：
            1、act_[x]_random_center:    记录当前center
            2、act_[x]_random_map:       存放包含数字映射的map（用于记录act_[x]_random_seed中的某个值映射到某个红包金额）
            3、act_[x]_random_seed:      存放包含[min,max*10]之间整数的的set（用于生成随机数）
          实现原理见：http://yapi.yijianxiu.com:7000/project/182/wiki
--]]



function math.randomMoney(act,remaining,min,max,center)
    min = 1
    local PREFIX_ = "act_"
    local _RANDOM_CENTER = "_random_center"
    local _RANDOM_MAP = "_random_map"
    local _RANDOM_SEED = "_random_seed"

    local key_of_center = PREFIX_..act.._RANDOM_CENTER;
    local key_of_map = PREFIX_..act.._RANDOM_MAP;
    local key_of_seed = PREFIX_..act.._RANDOM_SEED;

    -- 1、检测center，如果不存在或者值发生变化，则重新计算3个变量
    local c = redis.call('GET',key_of_center);
    if(c==nil or tonumber(c)~=center )
    then
        -- 1-1、计算1到max之间每个值的正态分布值
        local res = {};
        local d = 1.0;
        local c = center/max*10.0;
        local sum=0;
        local t = 0.01;
        for i=1,max,1 do
            local x = i/max*10.0;
            local y = math.exp(-math.pow((x-c),2)/(2*d))/math.sqrt(2*math.pi*d)  + t;
            table.insert(res,tostring(y));
            sum =sum +y;
        end;

        -- 1-2、计算比例
        local len = #res;
        for i=1,len,1 do
            res[i] =tostring(tonumber(res[i])/sum);
        end;

        -- 1-3、设置seed
        local len_of_seed = max*10;
        redis.call('DEL',key_of_seed);
        for i=1,len_of_seed,1 do
            redis.call('SADD',key_of_seed,i);
        end;

        -- 1-4、将seed映射到红包金额上
        redis.call('DEL',key_of_map);
        local lastEnd=0;
        for i=1,len,1 do
            local y = tonumber(res[i]) ;
            local len_of_tmp = math.ceil(y*len_of_seed );
            local s =  lastEnd+1;
            local e =  s+len_of_tmp-1;

            for j=s,e,1 do
                redis.call('HSET',key_of_map, j, i);
            end;
            lastEnd = e;
        end;
        -- 1-5、设置center
        redis.call('SET',key_of_center, center);
    end;


    -- 2、从seed中随机抽取一个值
    local seed = redis.call('SRANDMEMBER',key_of_seed);
    -- 3、到map中查询红包金额
    local v = redis.call('HGET',key_of_map,seed);

    -- 4、比较红包金额和余额
    if(v==nil)
    then
        v=0;
    elseif(tonumber(v)>remaining)
    then
        v=remaining
    end;
    -- 5、返回
    return v;
end